package com.listeningframework.boot.autoconfigure.security.overrides;

import com.listeningframework.boot.autoconfigure.security.ListeningSecurityProperties;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.User;

import javax.annotation.PostConstruct;
import java.util.Arrays;
import java.util.Collection;
import java.util.Date;
import java.util.stream.Collectors;

/**
 * @author lixining
 * @version $Id: JWTTokenProvider.java, v 0.1 2016年11月8日 下午12:05:46 lixining Exp $
 * JWT Provider
 */
public class JWTTokenProvider {
    private static final String AUTHORITIES_KEY = "auth";
    /**
     * Sign key
     */
    private String secretKey;
    /**
     * 有效时长
     */
    private long tokenValidityInSeconds;
    /**
     * 记住登陆-有效时长
     */
    private long tokenValidityInSecondsForRememberMe;
    /**
     * Config Properties
     */
    @Autowired
    private ListeningSecurityProperties properties;

    /**
     * 构造初始参数
     */
    @PostConstruct
    public void init() {
        this.secretKey = properties.getJwt().getSecret();
        this.tokenValidityInSeconds = 1000 * properties.getJwt().getTokenValidityInSeconds();
        this.tokenValidityInSecondsForRememberMe = 1000 * properties.getJwt().getTokenValidityInSecondsForRememberMe();
    }

    /**
     * 创建Spring Security Token
     *
     * @param authentication 认证信息
     * @param rememberMe 记住我
     * @return String
     */
    public String createToken(Authentication authentication, Boolean rememberMe) {
        String authorities = authentication.getAuthorities().stream().map(authority -> authority.getAuthority())
                .collect(Collectors.joining(","));
        long now = (new Date()).getTime();
        Date validity;
        if (rememberMe) {
            validity = new Date(now + this.tokenValidityInSecondsForRememberMe);
        } else {
            validity = new Date(now + this.tokenValidityInSeconds);
        }
        return Jwts.builder().setSubject(authentication.getName()).claim(AUTHORITIES_KEY, authorities)
                .signWith(SignatureAlgorithm.HS512, secretKey).setExpiration(validity).compact();
    }

    /**
     * Convert Token To Authentication
     *
     * @param token token值
     * @return Authentication
     */
    public Authentication getAuthentication(String token) {
        Claims claims = Jwts.parser().setSigningKey(secretKey).parseClaimsJws(token).getBody();
        Collection<? extends GrantedAuthority> authorities = Arrays
                .asList(claims.get(AUTHORITIES_KEY).toString().split(",")).stream()
                .map(authority -> new SimpleGrantedAuthority(authority)).collect(Collectors.toList());
        User principal = new User(claims.getSubject(), "", authorities);
        return new UsernamePasswordAuthenticationToken(principal, "", authorities);
    }

    /**
     * Parse Validate Token
     *
     * @param authToken 认证Token
     * @return Boolean
     */
    public boolean validateToken(String authToken) {
        try {
            Jwts.parser().setSigningKey(secretKey).parseClaimsJws(authToken);
            return true;
        } catch (Exception e) {
            return false;
        }
    }
}
